﻿#region Using Statements
using System;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Collections;
using System.Collections.Generic;
using Nexxt.Engine.Graphics.RayCast;
using Nexxt.Engine.GameObjects;
using Nexxt.UI.ScreenManager;   
#endregion

namespace Wolf3d.Screens
{
    /// <summary>
    /// This screen implements the actual wolf3d game logic.
    /// </summary>
    class GameplayScreen : GameScreen
    {
        #region Fields

        Effect spriteBatchShader;
        ContentManager content;
        SpriteFont gameFont;
        SpriteBatch spriteBatch;
        //our map
        Map map;

        //the camera
        Camera camera;

        //the renderer
        Renderer renderer;

        // Game Hud
        Texture2D hudTexture;
        #endregion

        #region Initialization


        /// <summary>
        /// Constructor.
        /// </summary>
        public GameplayScreen()
        {
            TransitionOnTime = TimeSpan.FromSeconds(1.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);   
        }
        /// <summary>
        /// Load graphics content for the game.
        /// </summary>
        public override void LoadContent()
        {
            if (content == null)
                content = new ContentManager(ScreenManager.Game.Services, "Content");

            spriteBatch = new SpriteBatch(this.ScreenManager.GraphicsDevice);

            gameFont = content.Load<SpriteFont>("Fonts/gameFont");   

            // LOAD MAP 

            //TODO: Somehow should be dynamic
            map = content.Load<Map>("Maps/e1m1");

            spriteBatchShader = content.Load<Effect>("Shaders/SpriteBatch");  

            // END LOAD MAP

            // load the Hud
            hudTexture = content.Load<Texture2D>("Hud/hud");   
            //load the font
            gameFont = content.Load<SpriteFont>("Fonts/Font");

            //create a new renderer at whaterever the preferred buffer size is
            renderer = new Renderer(
                ScreenManager.GraphicsDevice.Viewport.Width,
                ScreenManager.GraphicsDevice.Viewport.Height);

            camera = new Camera();

            //create some values for the Position and Direction.
            //Direction should be a normalized vector.
            camera.Position = new Vector2(57.82f, 28.30f);
            camera.Direction = new Vector2(0f, 1f);

            //determine the desired FOV
            float fov = .66f;

            //get the perpendicular vector to the Direction multiplying by the FOV
            camera.Plane = new Vector2(camera.Direction.Y, -camera.Direction.X) * fov;

            //store the camera in the static reference for sprite sorting
            Renderer.TempCamera = camera;

            // once the load has finished, we use ResetElapsedTime to tell the game's
            // timing mechanism that we have just finished a very long frame, and that
            // it should not try to catch up.
            ScreenManager.Game.ResetElapsedTime();
        }
        /// <summary>
        /// Unload graphics content used by the game.
        /// </summary>
        public override void UnloadContent()
        {
            content.Unload();
        }
        #endregion

        #region Update and Draw


        /// <summary>
        /// Updates the state of the game. This method checks the GameScreen.IsActive
        /// property, so the game will stop updating when the pause menu is active,
        /// or if you tab away to a different application.
        /// </summary>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            if (IsActive)
            {
#if !XBOX360
                camera.Update(
                    (float)gameTime.ElapsedGameTime.TotalSeconds,
                    Keyboard.GetState(),
                    map);
#else

                camera.Update(
                    (float)gameTime.ElapsedGameTime.TotalSeconds,
                    GamePad.GetState(PlayerIndex.One),
                    map);

#endif

                //update the renderer
                renderer.Update(map, camera);
            }
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
        }


        /// <summary>
        /// Lets the game respond to player input. Unlike the Update method,
        /// this will only be called when the gameplay screen is active.
        /// </summary>
        public override void HandleInput(InputState input)
        {
            if (input == null)
                throw new ArgumentNullException("input");

            // Look up inputs for the active player profile.
            int playerIndex = 1;//(int)ControllingPlayer.Value;

            KeyboardState keyboardState = input.CurrentKeyboardStates[playerIndex];
            GamePadState gamePadState = input.CurrentGamePadStates[playerIndex];

            // The game pauses either if the user presses the pause button, or if
            // they unplug the active gamepad. This requires us to keep track of
            // whether a gamepad was ever plugged in, because we don't want to pause
            // on PC if they are playing with a keyboard and have no gamepad at all!
            bool gamePadDisconnected = !gamePadState.IsConnected &&
                                       input.GamePadWasConnected[playerIndex];

            if (input.IsPauseGame(ControllingPlayer) || gamePadDisconnected)
            {
               // Pause Menu Screen
               ScreenManager.AddScreen(new PauseMenuScreen(), ControllingPlayer);
            }
            else
            {
                // Otherwise move the player position.
                
            }
        }


        int frameCount = 0;
        int totalTime = 0;
        int fps;
        private void calculateFPS(GameTime time)
        {
            frameCount++;

            totalTime += time.ElapsedGameTime.Milliseconds;

            if (totalTime > 1000)
            {
                fps = frameCount;
                frameCount = 0;
                totalTime = 0;
            }
        }


        /// <summary>
        /// Draws the gameplay screen.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {

            calculateFPS(gameTime);
            //draw the map. this draws the background and all the walls.
            renderer.Draw(spriteBatch, map);


            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
            Rectangle HudContainer = new Rectangle(0, 0, viewport.Width, viewport.Height);
            Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
            spriteBatchShader.Parameters["ViewportSize"].SetValue(viewportSize);


            //draw all the sprites
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);

            spriteBatchShader.Begin();
            spriteBatchShader.CurrentTechnique.Passes[0].Begin();



            // spriteBatch.Draw(hudTexture, HudContainer,Color.Wheat  ); 
            spriteBatch.DrawString(gameFont, "FPS:" + fps.ToString(), new Vector2(30, 40), Color.White);

           
            //Now the sprites are inside the map so handle the map to the renderer to render all the sprites
            renderer.DrawSprites(spriteBatch, map, camera);

            //draw the game Hud
            spriteBatch.Draw(hudTexture, HudContainer, Color.White);    

            spriteBatch.End();
            spriteBatchShader.CurrentTechnique.Passes[0].End();
            spriteBatchShader.End();

            // If the game is transitioning on or off, fade it out to black.
            if (TransitionPosition > 0)
                ScreenManager.FadeBackBufferToBlack(255 - TransitionAlpha);
        }


        #endregion
    }
}
